package com.zzzzzz.config;

import java.util.HashMap;
import java.util.Map;

import org.apache.shiro.authc.credential.DefaultPasswordService;
import org.apache.shiro.authc.credential.PasswordMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.crypto.hash.DefaultHashService;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import com.zzzzzz.account.signin.ShiroDbRealm;

@Configuration
public class SecurityConfig {
	
	@Bean(name = "passwordService")
	public DefaultPasswordService configPasswordService() {
		DefaultPasswordService passwordService = new DefaultPasswordService();
		DefaultHashService hashService = new DefaultHashService();
        hashService.setHashAlgorithmName("SHA-512");
        hashService.setHashIterations(1024);
        hashService.setGeneratePublicSalt(true);
        passwordService.setHashService(hashService);
		return passwordService;
	}
	
	@Bean(name = "passwordMatcher")
	public PasswordMatcher configPasswordMatcher(){
		PasswordMatcher passwordMatcher = new PasswordMatcher();
		passwordMatcher.setPasswordService(configPasswordService());
		return passwordMatcher;
	}
	
	@Bean
	public Realm configureRealm() {
		return new ShiroDbRealm();
	}
	
	@Bean(name = "securityManager")
	public DefaultWebSecurityManager configSecurityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(configureRealm());
		//securityManager.setCacheManager(configEhCacheManager());
		return securityManager;
	}
	
	/*private EhCacheManager configEhCacheManager() {
		EhCacheManager ehCacheManager = new EhCacheManager();
		ehCacheManager.setCacheManagerConfigFile("classpath:ehcache/ehcache-shiro.xml");
		return ehCacheManager;
	}*/
	
	
	@Bean(name = "shiroFilter")
	public ShiroFilterFactoryBean configShiroFilterFactoryBean() {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(configSecurityManager());
		shiroFilterFactoryBean.setLoginUrl("/login");
		shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(getFilterChainDefinitionMap());
		return shiroFilterFactoryBean;
	}
	
	private Map<String, String> getFilterChainDefinitionMap(){
		Map<String, String> filterChainDefinitionMap = new HashMap<String, String>();
		filterChainDefinitionMap.put("/login", "authc");
		filterChainDefinitionMap.put("/logout", "logout");
		filterChainDefinitionMap.put("/res/**", "anon");
		filterChainDefinitionMap.put("/logon", "authc");
		
		//topic
//		filterChainDefinitionMap.put("/article/add", "user");
//		filterChainDefinitionMap.put("/article/upload", "user");
//		filterChainDefinitionMap.put("/pictext/add", "user");
//		filterChainDefinitionMap.put("/picitem/add", "user");
//		filterChainDefinitionMap.put("/picitem/upload", "user");
		filterChainDefinitionMap.put("/topic/del/*", "user");
		filterChainDefinitionMap.put("/topic/edit/*", "user");
		filterChainDefinitionMap.put("/topic/*", "anon");
		filterChainDefinitionMap.put("/tag/*", "anon");
		filterChainDefinitionMap.put("/topic/like/*", "user");
		filterChainDefinitionMap.put("/topic/dislike/*", "user");
		filterChainDefinitionMap.put("/topic/unfeel/*", "user");
		
		//reply
		filterChainDefinitionMap.put("/content/reply/*", "user");
		
		//account
		filterChainDefinitionMap.put("/account/reset/**", "anon");
		filterChainDefinitionMap.put("/account/settings/**", "user");
		filterChainDefinitionMap.put("/userhome", "user");
		
		filterChainDefinitionMap.put("/signup", "anon");
		filterChainDefinitionMap.put("/account/is_email_existing", "anon");
		filterChainDefinitionMap.put("/account/activate/*", "anon");
		filterChainDefinitionMap.put("/account/resend_activation_email/*", "anon");
		filterChainDefinitionMap.put("/terms_of_service", "anon");
		
		return filterChainDefinitionMap;
	}
	
	@Bean(name = "lifecycleBeanPostProcessor")
	public LifecycleBeanPostProcessor configLifecycleBeanPostProcessor() {
		LifecycleBeanPostProcessor lifecycleBeanPostProcessor = new LifecycleBeanPostProcessor();
		return lifecycleBeanPostProcessor;
	}
	
	
	/**
	 * Enable Shiro Annotations for Spring-configured beans. Only run after the lifecycleBeanProcessor has run:
	 * @return
	 */
	@Bean(name = "annotationProxy")
	@DependsOn(value = { "lifecycleBeanPostProcessor" })	
	public DefaultAdvisorAutoProxyCreator configDefaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
		return defaultAdvisorAutoProxyCreator;
	}
	
	@Bean
	public AuthorizationAttributeSourceAdvisor configAuthorizationAttributeSourceAdvisor() {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(configSecurityManager());
		return authorizationAttributeSourceAdvisor;
	}
	
	/**
	 * Secure Spring remoting: Ensure any Spring Remoting method invocations can be associated with a Subject for security checks.
	 * @return
	 */
	@Bean(name = "secureRemoteInvocationExecutor")
	public SecureRemoteInvocationExecutor configSecureRemoteInvocationExecutor() {
		SecureRemoteInvocationExecutor secureRemoteInvocationExecutor = new SecureRemoteInvocationExecutor();
		secureRemoteInvocationExecutor.setSecurityManager(configSecurityManager());
		return secureRemoteInvocationExecutor;
	}
}
